1use crate::ext::io::*;
3use crate::ext::psb::*;
4use crate::scripts::base::*;
5use crate::types::*;
6use crate::utils::img::*;
7use crate::utils::psd::*;
8use crate::utils::struct_pack::*;
9use anyhow::Result;
10use emote_psb::PsbReader;
11use libtlg_rs::*;
12use std::collections::HashMap;
13use std::io::{Read, Seek};
14use std::path::Path;
15use std::sync::OnceLock;
16
17#[derive(Debug)]
19struct PImgOverlayState {
20 width: u32,
21 height: u32,
22 bases: HashMap<i64, (Tlg, u32, u32, u8)>,
23 base_id: i64,
24 all_non_diff: bool,
25}
26
27#[derive(Debug)]
28pub struct PImgBuilder {}
30
31impl PImgBuilder {
32 pub const fn new() -> Self {
34 Self {}
35 }
36}
37
38impl ScriptBuilder for PImgBuilder {
39 fn default_encoding(&self) -> Encoding {
40 Encoding::Utf8
41 }
42
43 fn build_script(
44 &self,
45 buf: Vec<u8>,
46 filename: &str,
47 _encoding: Encoding,
48 _archive_encoding: Encoding,
49 config: &ExtraConfig,
50 _archive: Option<&Box<dyn Script>>,
51 ) -> Result<Box<dyn Script + Send + Sync>> {
52 Ok(Box::new(PImg::new(MemReader::new(buf), filename, config)?))
53 }
54
55 fn build_script_from_file(
56 &self,
57 filename: &str,
58 _encoding: Encoding,
59 _archive_encoding: Encoding,
60 config: &ExtraConfig,
61 _archive: Option<&Box<dyn Script>>,
62 ) -> Result<Box<dyn Script + Send + Sync>> {
63 if filename == "-" {
64 let data = crate::utils::files::read_file(filename)?;
65 Ok(Box::new(PImg::new(MemReader::new(data), filename, config)?))
66 } else {
67 let f = std::fs::File::open(filename)?;
68 let reader = std::io::BufReader::new(f);
69 Ok(Box::new(PImg::new(reader, filename, config)?))
70 }
71 }
72
73 fn build_script_from_reader<'a>(
74 &self,
75 reader: Box<dyn ReadSeek + Send + Sync + 'a>,
76 filename: &str,
77 _encoding: Encoding,
78 _archive_encoding: Encoding,
79 config: &ExtraConfig,
80 _archive: Option<&Box<dyn Script>>,
81 ) -> Result<Box<dyn Script + Send + Sync + 'a>> {
82 Ok(Box::new(PImg::new(reader, filename, config)?))
83 }
84
85 fn extensions(&self) -> &'static [&'static str] {
86 &["pimg"]
87 }
88
89 fn script_type(&self) -> &'static ScriptType {
90 &ScriptType::EmotePimg
91 }
92
93 fn is_this_format(&self, filename: &str, buf: &[u8], buf_len: usize) -> Option<u8> {
94 if Path::new(filename)
95 .extension()
96 .map(|ext| ext.to_ascii_lowercase() == "pimg")
97 .unwrap_or(false)
98 && buf_len >= 4
99 && buf.starts_with(b"PSB\0")
100 {
101 return Some(255);
102 }
103 None
104 }
105
106 fn is_image(&self) -> bool {
107 true
108 }
109}
110
111struct PImgLayer<'a> {
112 data: &'a PsbValueFixed,
113 name: &'a str,
114 layer_id: i64,
115 layer_type: i64,
117 left: u32,
118 top: u32,
119 width: u32,
120 height: u32,
121 opacity: u8,
122 visible: bool,
123 type_: i64,
124 children: Vec<PImgLayer<'a>>,
125}
126
127impl std::fmt::Debug for PImgLayer<'_> {
128 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
129 f.debug_struct("PImgLayer")
130 .field("layer_id", &self.layer_id)
131 .field("layer_type", &self.layer_type)
132 .field("name", &self.name)
133 .field("left", &self.left)
134 .field("top", &self.top)
135 .field("width", &self.width)
136 .field("height", &self.height)
137 .field("opacity", &self.opacity)
138 .field("visible", &self.visible)
139 .field("type", &self.type_)
140 .field("children", &self.children)
141 .finish()
142 }
143}
144
145impl<'a> PImgLayer<'a> {
146 pub fn new(data: &'a PsbValueFixed, layers: &'a PsbValueFixed) -> Result<Self> {
147 let layer_id = data["layer_id"]
148 .as_i64()
149 .ok_or_else(|| anyhow::anyhow!("Layer does not have a valid layer_id"))?;
150 let layer_type = data["layer_type"]
151 .as_i64()
152 .ok_or_else(|| anyhow::anyhow!("Layer does not have a valid layer_type"))?;
153 let name = data["name"]
154 .as_str()
155 .ok_or_else(|| anyhow::anyhow!("Layer does not have a valid name"))?;
156 let left = data["left"].as_u32();
157 let top = data["top"].as_u32();
158 let width = data["width"].as_u32();
159 let height = data["height"].as_u32();
160 let (left, top, width, height) = if layer_type != 0 {
161 (
162 left.unwrap_or(0),
163 top.unwrap_or(0),
164 width.unwrap_or(0),
165 height.unwrap_or(0),
166 )
167 } else {
168 (
169 left.ok_or_else(|| anyhow::anyhow!("Layer does not have a valid left"))?,
170 top.ok_or_else(|| anyhow::anyhow!("Layer does not have a valid top"))?,
171 width.ok_or_else(|| anyhow::anyhow!("Layer does not have a valid width"))?,
172 height.ok_or_else(|| anyhow::anyhow!("Layer does not have a valid height"))?,
173 )
174 };
175 let opacity = data["opacity"]
176 .as_u8()
177 .ok_or_else(|| anyhow::anyhow!("Layer does not have a valid opacity"))?;
178 let visible = data["visible"].as_i64().unwrap_or(1) != 0;
179 let type_ = data["type"]
180 .as_i64()
181 .ok_or_else(|| anyhow::anyhow!("Layer does not have a valid type"))?;
182 let mut children = Vec::new();
183 for layer in layers.members() {
184 if layer_type == 2 || layer_type == 1 {
185 if let Some(parent_id) = layer["group_layer_id"].as_i64() {
186 if parent_id == layer_id {
187 children.push(PImgLayer::new(layer, layers)?);
188 }
189 }
190 } else if layer_type == 0 {
191 if let Some(base_id) = layer["diff_id"].as_i64() {
192 if base_id == layer_id {
193 children.push(PImgLayer::new(layer, layers)?);
194 }
195 }
196 }
197 }
198 Ok(Self {
199 data,
200 layer_id,
201 layer_type,
202 name,
203 left,
204 top,
205 width,
206 height,
207 opacity,
208 visible,
209 type_,
210 children,
211 })
212 }
213
214 fn len(&self) -> usize {
215 1 + self.children.iter().map(|c| c.len()).sum::<usize>()
216 }
217
218 fn load_img(&self, img: &PImg) -> Result<ImageData> {
219 if self.layer_type == 2 || self.layer_type == 1 {
220 anyhow::bail!("Group layers do not have image data");
221 }
222 if self.layer_id == -1 {
223 Ok(ImageData {
225 width: self.width,
226 height: self.height,
227 color_type: ImageColorType::Rgba,
228 depth: 8,
229 data: vec![0u8; (self.width * self.height * 4) as usize],
230 })
231 } else {
232 let tlg = img.load_img(self.layer_id).map_err(|e| {
233 anyhow::anyhow!("Failed to load image for layer_id {}: {}", self.layer_id, e)
234 })?;
235 let mut img = ImageData {
236 width: tlg.width,
237 height: tlg.height,
238 color_type: match tlg.color {
239 TlgColorType::Bgr24 => ImageColorType::Bgr,
240 TlgColorType::Bgra32 => ImageColorType::Bgra,
241 TlgColorType::Grayscale8 => ImageColorType::Grayscale,
242 },
243 depth: 8,
244 data: tlg.data.clone(),
245 };
246 convert_to_rgba(&mut img)?;
247 Ok(img)
248 }
249 }
250
251 fn save_to_psd(&self, img: &PImg, psd: &mut PsdWriter, base: &mut ImageData) -> Result<()> {
252 if self.children.is_empty() {
253 let img = self.load_img(img)?;
254 let mut visible = self.visible;
255 if !self.data["diff_id"].is_none() {
256 visible = false; }
258 if visible {
259 draw_on_img_with_opacity(base, &img, self.left, self.top, self.opacity)?;
260 }
261 let layer_name_source_setting = LayerNameSourceSetting {
262 id: self.layer_id as i32,
263 };
264 let mut packed = Vec::new();
265 layer_name_source_setting.pack(&mut packed, true, Encoding::Utf8, &None)?;
266 let additional_info = vec![AdditionalLayerInfo {
267 signature: *IMAGE_RESOURCE_SIGNATURE,
268 key: *LAYER_NAME_SOURCE_SETTING_KEY,
269 data: packed,
270 }];
271 let option = PsdLayerOption {
272 visible,
273 opacity: self.opacity,
274 additional_info,
275 };
276 psd.add_layer(self.name, self.left, self.top, img, Some(option))?;
277 } else {
278 psd.add_layer_group_end()?;
279 if self.layer_type == 0 {
280 let img = self.load_img(img)?;
281 let visible = self.visible;
282 if visible {
283 draw_on_img_with_opacity(base, &img, self.left, self.top, self.opacity)?;
284 }
285 let layer_name_source_setting = LayerNameSourceSetting {
286 id: self.layer_id as i32,
287 };
288 let mut packed = Vec::new();
289 layer_name_source_setting.pack(&mut packed, true, Encoding::Utf8, &None)?;
290 let additional_info = vec![AdditionalLayerInfo {
291 signature: *IMAGE_RESOURCE_SIGNATURE,
292 key: *LAYER_NAME_SOURCE_SETTING_KEY,
293 data: packed,
294 }];
295 let option = PsdLayerOption {
296 visible,
297 opacity: self.opacity,
298 additional_info,
299 };
300 psd.add_layer(self.name, self.left, self.top, img, Some(option))?;
301 }
302 for child in &self.children {
303 child.save_to_psd(img, psd, base)?;
304 }
305 let layer_name_source_setting = LayerNameSourceSetting {
306 id: self.layer_id as i32,
307 };
308 let mut packed = Vec::new();
309 layer_name_source_setting.pack(&mut packed, true, Encoding::Utf8, &None)?;
310 let additional_info = vec![AdditionalLayerInfo {
311 signature: *IMAGE_RESOURCE_SIGNATURE,
312 key: *LAYER_NAME_SOURCE_SETTING_KEY,
313 data: packed,
314 }];
315 let option = if self.layer_type == 0 {
316 Some(PsdLayerOption {
317 additional_info,
318 ..Default::default()
319 })
320 } else {
321 Some(PsdLayerOption {
322 visible: self.visible,
323 opacity: self.opacity,
324 additional_info,
325 })
326 };
327 psd.add_layer_group(self.name, self.layer_type == 2, option)?;
328 }
329 Ok(())
330 }
331}
332
333#[derive(Debug)]
334struct PImgLayerRoot<'a> {
335 layers: Vec<PImgLayer<'a>>,
336}
337
338impl<'a> PImgLayerRoot<'a> {
339 pub fn new(layers: &'a PsbValueFixed) -> Result<Self> {
340 let mut root_layers = Vec::new();
341 for layer in layers.members() {
342 if layer["group_layer_id"].is_none() && layer["diff_id"].is_none() {
343 root_layers.push(PImgLayer::new(layer, layers)?);
344 }
345 }
346 Ok(Self {
347 layers: root_layers,
348 })
349 }
350
351 fn len(&self) -> usize {
352 self.layers.iter().map(|l| l.len()).sum()
353 }
354
355 fn save_to_psd(&self, img: &PImg, psd: &mut PsdWriter, base: &mut ImageData) -> Result<()> {
356 for layer in &self.layers {
357 layer.save_to_psd(img, psd, base)?;
358 }
359 Ok(())
360 }
361}
362
363#[derive(Debug)]
364pub struct PImg {
366 psb: VirtualPsbFixed,
367 overlay: Option<bool>,
368 psd: bool,
369 psd_compress: bool,
370 zlib_compression_level: u32,
371 psd_no_diff: bool,
372 overlay_state: OnceLock<PImgOverlayState>,
373}
374
375impl PImg {
376 pub fn new<R: Read + Seek>(reader: R, _filename: &str, config: &ExtraConfig) -> Result<Self> {
382 let psb = PsbReader::open_psb_v2(reader)?.to_psb_fixed();
383 Ok(Self {
384 psb,
385 overlay: config.emote_pimg_overlay,
386 psd: config.emote_pimg_psd,
387 psd_compress: config.psd_compress,
388 zlib_compression_level: config.zlib_compression_level,
389 psd_no_diff: config.emote_pimg_psd_no_diff,
390 overlay_state: OnceLock::new(),
391 })
392 }
393
394 fn load_img(&self, layer_id: i64) -> Result<Tlg> {
395 let layer_id = layer_id as usize;
396 let psb = self.psb.root();
397 let reference = &psb[format!("{layer_id}.tlg")];
398 let resource_id = reference
399 .resource_id()
400 .ok_or_else(|| anyhow::anyhow!("Layer {layer_id} does not have a resource ID"))?
401 as usize;
402 if resource_id >= self.psb.resources().len() {
403 return Err(anyhow::anyhow!(
404 "Resource ID {resource_id} for layer {layer_id} is out of bounds"
405 ));
406 }
407 let resource = &self.psb.resources()[resource_id];
408 Ok(load_tlg(MemReaderRef::new(&resource))?)
409 }
410
411 fn overlay_mode(&self) -> bool {
413 let psb = self.psb.root();
414 self.overlay.unwrap_or_else(|| {
415 psb["layers"]
416 .members()
417 .all(|layer| layer["group_layer_id"].is_none())
418 })
419 }
420
421 fn compute_overlay_state(&self) -> Result<PImgOverlayState> {
423 let psb = self.psb.root();
424 let width = psb["width"]
425 .as_u32()
426 .ok_or(anyhow::anyhow!("missing width"))?;
427 let height = psb["height"]
428 .as_u32()
429 .ok_or(anyhow::anyhow!("missing height"))?;
430 let is_all_non_diff = psb["layers"]
431 .members()
432 .all(|layer| layer["diff_id"].is_none());
433 let mut bases = HashMap::new();
434 let mut base_id = None;
435 for i in psb["layers"].members() {
436 if !i["diff_id"].is_none() {
437 continue;
438 }
439 let layer_id = i["layer_id"]
440 .as_i64()
441 .ok_or(anyhow::anyhow!("missing layer_id"))?;
442 let top = i["top"].as_u32().ok_or(anyhow::anyhow!("missing top"))?;
443 let left = i["left"].as_u32().ok_or(anyhow::anyhow!("missing left"))?;
444 if is_all_non_diff {
445 let w = i["width"]
446 .as_u32()
447 .ok_or(anyhow::anyhow!("missing width for non-diff layer"))?;
448 let h = i["height"]
449 .as_u32()
450 .ok_or(anyhow::anyhow!("missing height for non-diff layer"))?;
451 if !(top == 0 && left == 0 && w == width && h == height) {
452 continue;
453 }
454 }
455 let opacity = i["opacity"]
456 .as_u8()
457 .ok_or_else(|| anyhow::anyhow!("Layer does not have a valid opacity"))?;
458 bases.insert(layer_id, (self.load_img(layer_id)?, top, left, opacity));
459 base_id = Some(layer_id);
460 }
461 Ok(PImgOverlayState {
462 width,
463 height,
464 bases,
465 base_id: base_id.ok_or(anyhow::anyhow!("No valid base layer found"))?,
466 all_non_diff: is_all_non_diff,
467 })
468 }
469
470 fn get_overlay_state(&self) -> Result<&PImgOverlayState> {
472 if let Some(state) = self.overlay_state.get() {
473 return Ok(state);
474 }
475 let state = self.compute_overlay_state()?;
476 Ok(self.overlay_state.get_or_init(|| state))
477 }
478}
479
480impl Script for PImg {
481 fn default_output_script_type(&self) -> OutputScriptType {
482 OutputScriptType::Custom
483 }
484
485 fn is_output_supported(&self, output: OutputScriptType) -> bool {
486 matches!(output, OutputScriptType::Custom)
487 }
488
489 fn custom_output_extension<'a>(&'a self) -> &'a str {
490 "psd"
491 }
492
493 fn default_format_type(&self) -> FormatOptions {
494 FormatOptions::None
495 }
496
497 fn is_image(&self) -> bool {
498 !self.psd
499 }
500
501 fn is_multi_image(&self) -> bool {
502 !self.psd
503 }
504
505 fn iter_multi_image_name<'a>(
506 &'a self,
507 ) -> Result<Box<dyn Iterator<Item = Result<String>> + 'a>> {
508 let psb = self.psb.root();
509 if !self.overlay_mode() {
510 Ok(Box::new(
511 psb.iter()
512 .filter(|(k, _)| k.ends_with(".tlg"))
513 .map(|(k, _)| Ok(k.trim_end_matches(".tlg").to_string())),
514 ))
515 } else {
516 if !psb["layers"].is_list() {
517 return Err(anyhow::anyhow!("layers is not a list"));
518 }
519 Ok(Box::new(psb["layers"].members().map(|layer| {
520 layer["name"]
521 .as_str()
522 .map(|s| s.to_string())
523 .ok_or_else(|| anyhow::anyhow!("Layer does not have a valid name"))
524 })))
525 }
526 }
527
528 fn open_image<'a>(&'a self, index: usize) -> Result<ImageDataWithName> {
529 let psb = self.psb.root();
530 if !self.overlay_mode() {
531 let mut count = 0;
533 for (k, v) in psb.iter() {
534 if !k.ends_with(".tlg") {
535 continue;
536 }
537 if count == index {
538 let resource_id = v
539 .resource_id()
540 .ok_or_else(|| anyhow::anyhow!("Layer {} does not have a resource ID", k))?
541 as usize;
542 let name = k.trim_end_matches(".tlg").to_string();
543 if resource_id >= self.psb.resources().len() {
544 return Err(anyhow::anyhow!(
545 "Resource ID {} for layer {} is out of bounds",
546 resource_id,
547 k
548 ));
549 }
550 let resource = &self.psb.resources()[resource_id];
551 let tlg = load_tlg(MemReaderRef::new(resource))?;
552 return Ok(ImageDataWithName {
553 name,
554 data: ImageData {
555 width: tlg.width,
556 height: tlg.height,
557 color_type: match tlg.color {
558 TlgColorType::Bgr24 => ImageColorType::Bgr,
559 TlgColorType::Bgra32 => ImageColorType::Bgra,
560 TlgColorType::Grayscale8 => ImageColorType::Grayscale,
561 },
562 depth: 8,
563 data: tlg.data.clone(),
564 },
565 });
566 }
567 count += 1;
568 }
569 Err(anyhow::anyhow!("Layer index {} out of bounds", index))
570 } else {
571 let state = self.get_overlay_state()?;
573 let layer = psb["layers"]
574 .members()
575 .nth(index)
576 .ok_or_else(|| anyhow::anyhow!("Layer index {} out of bounds", index))?;
577 let layer_id = layer["layer_id"]
578 .as_i64()
579 .ok_or_else(|| anyhow::anyhow!("Layer does not have a valid layer_id"))?;
580 let layer_name = layer["name"]
581 .as_str()
582 .ok_or_else(|| anyhow::anyhow!("Layer does not have a valid name"))?;
583 let width = layer["width"]
584 .as_u32()
585 .ok_or_else(|| anyhow::anyhow!("Layer does not have a valid width"))?;
586 let height = layer["height"]
587 .as_u32()
588 .ok_or_else(|| anyhow::anyhow!("Layer does not have a valid height"))?;
589 let top = layer["top"]
590 .as_u32()
591 .ok_or_else(|| anyhow::anyhow!("Layer does not have a valid top"))?;
592 let left = layer["left"]
593 .as_u32()
594 .ok_or_else(|| anyhow::anyhow!("Layer does not have a valid left"))?;
595 let opacity = layer["opacity"]
596 .as_u8()
597 .ok_or_else(|| anyhow::anyhow!("Layer does not have a valid opacity"))?;
598 if (layer["diff_id"].is_none() && !state.all_non_diff)
599 || (state.all_non_diff && layer_id == state.base_id)
600 {
601 let base = &state
603 .bases
604 .get(&layer_id)
605 .ok_or_else(|| {
606 anyhow::anyhow!("Base image for layer_id {} not found", layer_id)
607 })?
608 .0;
609 let mut data = ImageData {
610 width: state.width,
611 height: state.height,
612 color_type: match base.color {
613 TlgColorType::Bgr24 => ImageColorType::Bgr,
614 TlgColorType::Bgra32 => ImageColorType::Bgra,
615 TlgColorType::Grayscale8 => ImageColorType::Grayscale,
616 },
617 depth: 8,
618 data: base.data.clone(),
619 };
620 if opacity != 255 {
621 apply_opacity(&mut data, opacity)?;
622 }
623 if state.width != width || state.height != height || top != 0 || left != 0 {
624 data = draw_on_canvas(data, state.width, state.height, left, top)?;
625 }
626 Ok(ImageDataWithName {
627 name: layer_name.to_string(),
628 data,
629 })
630 } else {
631 let diff_id = if state.all_non_diff {
633 state.base_id
634 } else {
635 layer["diff_id"]
636 .as_i64()
637 .ok_or_else(|| anyhow::anyhow!("Layer does not have a valid diff_id"))?
638 };
639 let (base, base_top, base_left, base_opacity) = state
640 .bases
641 .get(&diff_id)
642 .ok_or_else(|| anyhow::anyhow!("Base image layer {} not found", diff_id))?;
643 let diff = self.load_img(layer_id)?;
644 if base.color != diff.color {
645 return Err(anyhow::anyhow!(
646 "Color type mismatch for layer_id {}: base color {:?}, diff color {:?}",
647 layer_id,
648 base.color,
649 diff.color
650 ));
651 }
652 let mut base_img = ImageData {
653 width: base.width,
654 height: base.height,
655 color_type: match base.color {
656 TlgColorType::Bgr24 => ImageColorType::Bgr,
657 TlgColorType::Bgra32 => ImageColorType::Bgra,
658 TlgColorType::Grayscale8 => ImageColorType::Grayscale,
659 },
660 depth: 8,
661 data: base.data.clone(),
662 };
663 if base.width != state.width
664 || base.height != state.height
665 || *base_top != 0
666 || *base_left != 0
667 {
668 base_img =
669 draw_on_canvas(base_img, state.width, state.height, *base_left, *base_top)?;
670 }
671 if *base_opacity != 255 {
672 apply_opacity(&mut base_img, *base_opacity)?;
673 }
674 let diff_img = ImageData {
675 width: diff.width,
676 height: diff.height,
677 color_type: match diff.color {
678 TlgColorType::Bgr24 => ImageColorType::Bgr,
679 TlgColorType::Bgra32 => ImageColorType::Bgra,
680 TlgColorType::Grayscale8 => ImageColorType::Grayscale,
681 },
682 depth: 8,
683 data: diff.data.clone(),
684 };
685 draw_on_img_with_opacity(&mut base_img, &diff_img, left, top, opacity)?;
686 Ok(ImageDataWithName {
687 name: layer_name.to_string(),
688 data: base_img,
689 })
690 }
691 }
692 }
693
694 fn custom_export(&self, filename: &std::path::Path, encoding: Encoding) -> Result<()> {
695 let psb = self.psb.root();
696 let width = psb["width"]
697 .as_u32()
698 .ok_or(anyhow::anyhow!("missing width"))?;
699 let height = psb["height"]
700 .as_u32()
701 .ok_or(anyhow::anyhow!("missing height"))?;
702 let mut psd = PsdWriter::new(width, height, ImageColorType::Rgba, 8, encoding)?
703 .compress(self.psd_compress)
704 .zlib_compression_level(self.zlib_compression_level);
705 let mut base = ImageData {
706 width,
707 height,
708 color_type: ImageColorType::Rgba,
709 depth: 8,
710 data: vec![0u8; (width * height * 4) as usize],
711 };
712 if !self.psd_no_diff {
713 let is_no_group = psb["layers"]
714 .members()
715 .all(|layer| layer["group_layer_id"].is_none());
716 let is_all_non_diff = psb["layers"]
717 .members()
718 .all(|layer| layer["diff_id"].is_none());
719 if is_all_non_diff && is_no_group {
720 let mut psb = psb.clone();
721 let diff_id = {
722 let base_layer = psb["layers"]
723 .members()
724 .rev()
725 .find(|layer| {
726 layer["diff_id"].is_none()
727 && layer["top"].as_i64() == Some(0)
728 && layer["left"].as_i64() == Some(0)
729 && layer["width"].as_u32() == Some(width)
730 && layer["height"].as_u32() == Some(height)
731 })
732 .ok_or(anyhow::anyhow!(
733 "No valid base layer found for overlay mode"
734 ))?;
735 base_layer["layer_id"]
736 .as_i64()
737 .ok_or(anyhow::anyhow!("missing layer_id for base layer"))?
738 };
739 for layer in psb["layers"].members_mut() {
740 let layer_id = layer["layer_id"].as_i64().unwrap_or(-1);
741 if layer_id != diff_id {
742 layer["diff_id"] = diff_id.into();
743 }
744 }
745 let layers = PImgLayerRoot::new(&psb["layers"])?;
746 if layers.len() != psb["layers"].len() {
747 return Err(anyhow::anyhow!("Layer hierarchy is invalid"));
748 }
749 layers.save_to_psd(self, &mut psd, &mut base)?;
750 let file = std::fs::File::create(filename)?;
751 let mut writer = std::io::BufWriter::new(file);
752 psd.save(base, &mut writer)?;
753 return Ok(());
754 }
755 }
756 let layers = PImgLayerRoot::new(&psb["layers"])?;
757 if layers.len() != psb["layers"].len() {
758 return Err(anyhow::anyhow!("Layer hierarchy is invalid"));
759 }
760 layers.save_to_psd(self, &mut psd, &mut base)?;
761 let file = std::fs::File::create(filename)?;
762 let mut writer = std::io::BufWriter::new(file);
763 psd.save(base, &mut writer)?;
764 Ok(())
765 }
766}